package com.tcm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tcm.config.AppProperties;
import com.tcm.entity.Code;
import com.tcm.entity.CodeType;
import com.tcm.entity.dto.CodeUpdateDto;
import com.tcm.entity.resp.PageR;
import com.tcm.entity.vo.CodeTypeResult;
import com.tcm.exception.DatabaseOperationException;
import com.tcm.exception.EntityAlreadyExistException;
import com.tcm.mapper.CodeMapper;
import com.tcm.mapper.CodeTypeMapper;
import com.tcm.service.CodeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * 码表管理业务实现类
 * @author Guqier
 * @version 1.0
 * @date 2023/7/2 17:06
 */
@Slf4j
@Service
public class CodeServiceImpl extends ServiceImpl<CodeMapper, Code> implements CodeService {

    @Autowired
    private CodeTypeMapper typeMapper;

    @Autowired
    private CodeMapper codeMapper;

    /**
     * 根据ID获取码表（缓存）
     * @param id ID
     * @return 码表对象
     */
    @Override
    @Cacheable(value = AppProperties.ENTITY_CACHE_CODE, key = "#id", unless = "#result == null")
    public Code getCodeById(Long id) {
        return this.getById(id);
    }

    /**
     * 根据ID删除码表（缓存）
     * @param id 码表ID
     * @return 结果
     */
    @Override
    @CacheEvict(value = AppProperties.ENTITY_CACHE_CODE, key = "#id", condition = "#id != null")
    public boolean removeCodeById(Long id) {
        return this.removeById(id);
    }

    /**
     * 更新码表信息（缓存）
     * @param code 码表对象
     * @return 结果
     */
    @Override
    @CacheEvict(value = AppProperties.ENTITY_CACHE_CODE, key = "#code.id", condition = "#code.id != null")
    public boolean updateCodeById(Code code) {
        return this.updateById(code);
    }

    /**
     * 获取码表类型列表
     * @return 码表类型列表
     */
    @Override
    public List<CodeTypeResult> getCodeType(){
        List<CodeTypeResult> results = new ArrayList<>();
        List<CodeType> codeTypes = typeMapper.selectList(null);
        for (CodeType codeType : codeTypes) {
            CodeTypeResult codeTypeResult = new CodeTypeResult();
            BeanUtils.copyProperties(codeType, codeTypeResult);
            results.add(codeTypeResult);
        }
        return results;
    }

    /**
     * 添加码表
     * @param codeUpdateDto 码表更新信息数据封装对象
     * @param currUserId 当前登录用户ID
     * @return 执行结果，true为成功
     */
    @Override
    @Transactional
    public boolean addCode(CodeUpdateDto codeUpdateDto, Long currUserId) throws EntityAlreadyExistException{
        // 判断sequence是否为空
        if (codeUpdateDto.getSequence() == null) {
            codeUpdateDto.setSequence(1);
        }
        // 判断类型是否存在
        LambdaQueryWrapper<CodeType> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CodeType::getType, codeUpdateDto.getType());
        CodeType codeType = typeMapper.selectOne(queryWrapper);
        if (codeType == null){
            return false;
        }
        // 判断同类型下是否存在同code
        LambdaQueryWrapper<Code> queryWrapperCode = new LambdaQueryWrapper<>();
        queryWrapperCode.eq(Code::getCode, codeUpdateDto.getCode())
                .eq(Code::getType, codeUpdateDto.getType());
        queryWrapperCode.orderByAsc(Code::getSequence);
        Code one = codeMapper.selectOne(queryWrapperCode);
        if (one != null){
            throw new EntityAlreadyExistException("码表已存在");
        }

        Code code = new Code();
        BeanUtils.copyProperties(codeUpdateDto, code);// 给Code实体类赋值
        code.setCreateUser(currUserId);
        code.setUpdateUser(currUserId);

        int res = codeMapper.insert(code);
        return res == 1;
    }

    /**
     * 分页获取码表列表
     * @param pageNum 当前页数
     * @param pageSize 当前页大小
     * @param type 查询类型
     * @return 码表列表
     */
    @Override
    public PageR<CodeUpdateDto> getCodeListByPage(Integer pageNum, Integer pageSize, String type){
        // 分页构造器
        Page<Code> page = new Page<>(pageNum, pageSize);
        page.addOrder(OrderItem.desc("update_time"));
        // 条件构造器
        LambdaQueryWrapper<Code> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.hasText(type)){// 如果type为空，则返回所有码表数据
            queryWrapper.eq(Code::getType, type);
        }
        // 查询数据库获得分页信息
        codeMapper.selectPage(page, queryWrapper);

        // 获取码表类型名称
        List<CodeType> codeTypes = typeMapper.selectList(null);
        Map<String, String> typeNameMap = new HashMap<>();
        for (CodeType codeType : codeTypes) {
            typeNameMap.put(codeType.getType(), codeType.getName());
        }

        // 给响应对象赋值
        List<Code> codes = page.getRecords();
        List<CodeUpdateDto> list = new LinkedList<>();
        for (Code code : codes) {
            CodeUpdateDto codeUpdateDto = new CodeUpdateDto();
            BeanUtils.copyProperties(code, codeUpdateDto);
            codeUpdateDto.setTypeName(typeNameMap.get(code.getType()));
            list.add(codeUpdateDto);
        }

        PageR<CodeUpdateDto> pageR = new PageR<>();
        BeanUtils.copyProperties(page, pageR);
        pageR.setRecords(list);
        return pageR;
    }

    /**
     * 删除码表接口
     * @param ids id集合
     * @param currUserId 当前登录用户信息
     * @return 删除结果，true为成功
     */
    @Override
    @Transactional
    public boolean dropCodeByIds(List<Long> ids, Long currUserId) throws DatabaseOperationException {
        int cnt = 0;// 总删除数
        for (Long id : ids) {
            // 修改更新用户ID
            Code code = codeMapper.selectById(id);
            if (code == null || AppProperties.CODE_DELETE_DISABLE_TYPE.contains(code.getType())) {
                continue;
            }
            code.setUpdateUser(currUserId);
            codeMapper.updateById(code);

            // 删除当前ID所指Code
            boolean res = this.removeCodeById(id);
            if (res) {
                cnt++;
            }
        }
        if (cnt != ids.size()){
            throw new DatabaseOperationException("数据库操作异常");
        }
        return true;
    }

    /**
     * 修改码表信息
     * @param codeUpdateDto 码表信息封装对象
     * @param currUserId 当前登录用户ID
     * @return 修改结果，true为成功
     */
    @Override
    @Transactional
    public boolean modifyCode(CodeUpdateDto codeUpdateDto, Long currUserId){
        // 查询是否存在
        Code code = codeMapper.selectById(codeUpdateDto.getId());
        if (code == null){
            return false;// 不存在
        }
        // 判断类型是否存在
        LambdaQueryWrapper<CodeType> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CodeType::getType, codeUpdateDto.getType());
        CodeType codeType = typeMapper.selectOne(queryWrapper);
        if (codeType == null) {
            return false;
        }
        // 执行修改
        BeanUtils.copyProperties(codeUpdateDto, code);
        code.setUpdateUser(currUserId);
        return this.updateCodeById(code);
    }

    /**
     * 获取年级列表
     * @return 年级列表
     */
    @Override
    public List<Code> getGradeList(){
        LambdaQueryWrapper<Code> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Code::getType, "grade");
        return codeMapper.selectList(queryWrapper);
    }
}
